package com.xianzhi.dao.interceptor;


import com.xianzhi.bean.BaseBean;
import com.xianzhi.util.Page;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
 * 创建一个自定义的拦截器（基本的原理是基于动态代理来实现的）
 * @Intercepts表示当前定义的类是一个自定义拦截器
 * @Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class})
 * 表示我们要拦截StatementHandler对象中的prepare(Connection conn)方法  args:方法参数的类型
 */
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class})})
public class PageInterceptor implements Interceptor {
    /**
     * intercept(Invocation invocation) 核心的拦截器方法
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取到目标对象
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        //获取到元数据对象,之后我们就可以从这个对象MetaObject中的方法获中取到我们要处理（拦截的操作）
        MetaObject metaObject  =  MetaObject.forObject(
                statementHandler,
                SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
                new DefaultReflectorFactory());
        //根据key获取到映射对象 MappedStatement--------------AdDao.xml
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        //获取到要拦截操作的id
        String id =  mappedStatement.getId();
        if(id.endsWith("ByPage")) {
            //获取到拦截操作的sql语句
            BoundSql boundSql =  statementHandler.getBoundSql();
            //获取到AdDao.xml中的SQL语句
            String sql = boundSql.getSql();
            //计算总的记录数
            String countsql = "select count(*) from("+sql+")t";
            //获取到 prepare（Connection con） Connection接口
            Connection connection =(Connection) invocation.getArgs()[0];
            PreparedStatement preparedStatement = connection.prepareStatement(countsql);
            //通过元数据获取到ParameterHandler对象,目的是将?替换成具体的值
            ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(preparedStatement);
            //执行查询
            ResultSet rs = preparedStatement.executeQuery();
            //通过BoundSql方法来获取到分页的BaseBean对象
            BaseBean bean =(BaseBean) boundSql.getParameterObject();
            Page page = bean.getPage();
            if(rs.next()) {
                //将总记录数获取到并赋值给Page中的totalNumber属性
                page.setTotalNumber(rs.getInt(1));
            }
            //完成分页的sql:select * from table limit (currentPage-1)*pageSize,pageSize
            //select id,title,img_file_name,link,weight from ad limit(m,n)
            String pageSql = sql+" limit "+(page.getCurrentPage()-1)*page.getPageNumber()+","+page.getPageNumber();
            //重写分页的sql
            metaObject.setValue("delegate.boundSql.sql",pageSql);
        }
        //将执行权交给下一个拦截器,如果没有的话再将资源交给controller
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o,this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}